﻿using System;
using System.Collections.Generic;
using System.Text;
using Spring.Scheduling.Quartz;
using DotNetServiceLib.Core;
using Common.Logging;

namespace DotNetServiceLib.Core
{
    /// <summary>
    /// Allows to exchange data from one assembly's instance method to another instance method.
    /// No interface needs to be implement on any side and no class needs to be made available as a remote object.  
    /// This is not a good solution if you 1) need to execute long duration invocation 2) need to exchange complex data structure 3) need to handle concurrency
    /// But it is a pretty handy solution if 1) you have no way to recompile the assemblies 2) the data your exchanging are native types 3) no long invocation is required ) you don't have problem with the overhead of box & unboxing the data that is beeing exchanged
    /// The first method invoked can receive any number of value type parameters and System.String type. The returning object must also be a value type or a System.String.
    /// The second method gets invoked with the return value from the first invocation and any additional parameter provided.
    /// </summary>
    public class TaskMethodInterop : QuartzJobObject, ITask
    {
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private string name = "";
        private string target = "";
        private string arguments = "";
        private bool loggingIsEnabled = true;
        private string className = "";
        private string methodName = "";
        private string targetDestination = "";
        private string classNameDestination = "";
        private string methodNameDestination = "";
        private string argumentsDestination = "";
        private List<KeyValuePair<string, string>> listOfArguments;
        private List<KeyValuePair<string, string>> listOfArgumentsDestination;

        protected override void ExecuteInternal(Quartz.JobExecutionContext context)
        {
            /// targetDestination should be configured using AppDomain.CurrentDomain.BaseDirectory. This way there is no need to 
            /// give the complete path to the assembly.
            /// The task should try both ways: load with and without the AppDomain.CurrentDomain.BaseDirectory.

            MethodActivator methodActivator = new MethodActivator();
            methodActivator.LoggingIsEnabled = loggingIsEnabled;
            object returnValue = null;
            listOfArguments = methodActivator.ProcessArguments(arguments);
            methodActivator.Fire(target, className, methodName, listOfArguments, ref returnValue);
            if (returnValue != null)
            {
                argumentsDestination = argumentsDestination.Replace("returnValue", returnValue.ToString());
                listOfArgumentsDestination = methodActivator.ProcessArguments(argumentsDestination);
                methodActivator.Fire(targetDestination, classNameDestination, methodNameDestination, listOfArgumentsDestination);
            }
            else
                log.Error(String.Format("Invoking method '{0}' on class '{1}' had no result value.", methodName, className));
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        public string Target
        {
            get
            {
                return target;
            }
            set
            {
                target = value;
            }
        }
        public string Arguments
        {
            get
            {
                return arguments;
            }
            set
            {
                arguments = value;
            }
        }
        public bool LoggingIsEnabled
        {
            get
            {
                return loggingIsEnabled;
            }
            set
            {
                loggingIsEnabled = value;
            }
        }
        public string ClassName
        {
            get
            {
                return className;
            }
            set
            {
                className = value;
            }
        }
        public string MethodName
        {
            get
            {
                return methodName;
            }
            set
            {
                methodName = value;
            }
        }
        public string TargetDestination
        {
            get
            {
                return targetDestination;
            }
            set
            {
                targetDestination = value;
            }
        }
        public string ClassNameDestination
        {
            get
            {
                return classNameDestination;
            }
            set
            {
                classNameDestination = value;
            }
        }
        public string MethodNameDestination
        {
            get
            {
                return methodNameDestination;
            }
            set
            {
                methodNameDestination = value;
            }
        }
        public string ArgumentsDestination
        {
            get
            {
                return argumentsDestination;
            }
            set
            {
                argumentsDestination = value;
            }
        }
    }
}
